home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume4 / uemacs / part2 < prev    next >
Encoding:
Internet Message Format  |  1986-11-30  |  46.4 KB

  1. From: genrad!decvax!minow (Martin Minow)
  2. Subject: MicroEmacs (Part 2 of 6)
  3. Newsgroups: mod.sources
  4. Approved: jpn@panda.UUCP
  5.  
  6. Mod.sources:  Volume 4, Issue 69
  7. Submitted by: decvax!minow (Martin Minow)
  8.  
  9. #! /bin/sh
  10. # This is a shell archive, meaning:
  11. # 1. Remove everything above the #! /bin/sh line.
  12. # 2. Save the resulting text in a file.
  13. # 3. Execute the file with /bin/sh (not csh) to create the files:
  14. #    echo.c
  15. #    extend.c
  16. #    file.c
  17. #    kbd.c
  18. #    line.c
  19. #    main.c
  20. # This archive created: Sun Apr 13 11:15:48 1986
  21. export PATH; PATH=/bin:$PATH
  22. echo shar: extracting "'echo.c'" '(8844 characters)'
  23. if test -f 'echo.c'
  24. then
  25.     echo shar: will not over-write existing file "'echo.c'"
  26. else
  27. cat << \SHAR_EOF > 'echo.c'
  28. /*
  29.  * Name:    MicroEMACS
  30.  *        Echo line reading and writing.
  31.  * Version:    29
  32.  * Last edit:    14-Feb-86
  33.  * By:        rex::conroy
  34.  *        decvax!decwrl!dec-rhea!dec-rex!conroy
  35.  *
  36.  * Common routines for reading
  37.  * and writing characters in the echo line area
  38.  * of the display screen. Used by the entire
  39.  * known universe.
  40.  */
  41. #include    "def.h"
  42.  
  43. int    epresf    = FALSE;        /* Stuff in echo line flag.    */
  44. int    nmsg    = 0;            /* Size of occupied msg. area.    */
  45. int    curmsgf    = FALSE;        /* Current alert state.        */
  46. int    newmsgf    = FALSE;        /* New alert state.        */
  47.  
  48. char    msg[NMSG];            /* Random message storage.    */
  49.  
  50. /*
  51.  * Send a string to the message system.
  52.  * Add a free newline to the end of the message string.
  53.  * Return TRUE if it fits, and FALSE if it does not.
  54.  * Perhaps the message buffer should know how to get
  55.  * larger, just like the kill buffer?
  56.  */
  57. writemsg(sp)
  58. register char    *sp;
  59. {
  60.     register int    c;
  61.  
  62.     if (nmsg+strlen(sp)+1 > NMSG)        /* "+1" for the "\n".    */
  63.         return (FALSE);
  64.     while ((c = *sp++) != '\0')
  65.         msg[nmsg++] = c;
  66.     msg[nmsg++] = '\n';
  67.     newmsgf = TRUE;                /* Update mode line.    */
  68.     return (TRUE);
  69. }
  70.  
  71. /*
  72.  * Read messages. The message lines are
  73.  * displayed, one line at a time, in the message line.
  74.  * A special sub-mode is entered, in which the keys have
  75.  * the following meanings:
  76.  *    ^P    Go backward 1 line.
  77.  *    BS    Go backward 1 line.
  78.  *    ^N    Go forward 1 line. Quit if at the end.
  79.  *    SP    Go forward 1 line. Quit if at the end.
  80.  *    CR    Go forward 1 line. Quit if at the end.
  81.  *    ^G    Abort, leave old text.
  82.  *    ^C    Quit, delete anything already read.
  83.  * Return TRUE if you left this mode in a reasonable
  84.  * way (not ^G), and ABORT if you quit the mode with a
  85.  * ^G.
  86.  */
  87. readmsg()
  88. {
  89.     register int    c;
  90.     register int    i;
  91.     register int    j;
  92.  
  93.     if (nmsg == 0)                /* Duck out if none.    */
  94.         return (TRUE);
  95.     newmsgf = FALSE;            /* Kill alert, and do    */
  96.     update();                /* a redisplay.        */
  97.     ttcolor(CTEXT);
  98.     i = 0;
  99.     while (i < nmsg) {
  100.         ttmove(nrow-1, 0);        /* Display 1 line.    */
  101.         while (i<nmsg && (c=msg[i++])!='\n')
  102.             eputc(c);
  103.         tteeol();
  104.         ttmove(nrow-1, 0);        /* Looks nice.        */
  105.         ttflush();
  106.         for (;;) {            /* Editing loop.    */
  107.             c = ttgetc();
  108.             switch (c) {
  109.             case 0x0E:        /* ^N            */
  110.             case 0x20:        /* SP            */
  111.             case 0x0D:        /* CR            */
  112.                 break;
  113.  
  114.             case 0x10:        /* ^P            */
  115.             case 0x08:        /* BS            */
  116.                 do {
  117.                     --i;
  118.                 } while (i!=0 && msg[i-1]!='\n');
  119.                 if (i != 0) {
  120.                     do {    /* Back up 1 line.    */
  121.                         --i;
  122.                     } while (i!=0 && msg[i-1]!='\n');
  123.                 }
  124.                 break;
  125.  
  126.             case 0x03:        /* ^C            */
  127.                 j = 0;        /* Eat what we read.    */
  128.                 while (i < nmsg)
  129.                     msg[j++] = msg[i++];
  130.                 nmsg = j;
  131.                 eerase();
  132.                 return (TRUE);
  133.  
  134.             case 0x07:        /* ^G            */
  135.                 ttbeep();
  136.                 eerase();
  137.                 return (ABORT);
  138.  
  139.             default:        /* Loop on the rest.    */
  140.                 continue;
  141.             }
  142.             break;
  143.         }                
  144.     }    
  145.     nmsg = 0;                /* Flow off the end.    */
  146.     eerase();
  147.     return (TRUE);
  148. }
  149.  
  150. /*
  151.  * Erase the echo line.
  152.  */
  153. eerase()
  154. {
  155.     ttcolor(CTEXT);
  156.     ttmove(nrow-1, 0);
  157.     tteeol();
  158.     ttflush();
  159.     epresf = FALSE;
  160. }
  161.  
  162. /*
  163.  * Ask "yes" or "no" question.
  164.  * Return ABORT if the user answers the question
  165.  * with the abort ("^G") character. Return FALSE
  166.  * for "no" and TRUE for "yes". No formatting
  167.  * services are available.
  168.  */
  169. eyesno(sp)
  170. char    *sp;
  171. {
  172.     register int    s;
  173.     char        buf[64];
  174.  
  175.     for (;;) {
  176.         s = ereply("%s [y/n]? ", buf, sizeof(buf), sp);
  177.         if (s == ABORT)
  178.             return (ABORT);
  179.         if (s != FALSE) {
  180.             if (buf[0]=='y' || buf[0]=='Y')
  181.                 return (TRUE);
  182.             if (buf[0]=='n' || buf[0]=='N')
  183.                 return (FALSE);
  184.         }
  185.     }
  186. }
  187.  
  188. /*
  189.  * Write out a prompt, and read back a
  190.  * reply. The prompt is now written out with full "eprintf"
  191.  * formatting, although the arguments are in a rather strange
  192.  * place. This is always a new message, there is no auto
  193.  * completion, and the return is echoed as such.
  194.  */
  195. /* VARARGS3 */
  196. ereply(fp, buf, nbuf, arg)
  197. char    *fp;
  198. char    *buf;
  199. {
  200.     return (eread(fp, buf, nbuf, EFNEW|EFCR, (char *)&arg));
  201. }
  202.  
  203. /*
  204.  * This is the general "read input from the
  205.  * echo line" routine. The basic idea is that the prompt
  206.  * string "prompt" is written to the echo line, and a one
  207.  * line reply is read back into the supplied "buf" (with
  208.  * maximum length "len"). The "flag" contains EFNEW (a
  209.  * new prompt), an EFAUTO (autocomplete), or EFCR (echo
  210.  * the carriage return as CR).
  211.  */
  212. eread(fp, buf, nbuf, flag, ap)
  213. char    *fp;
  214. char    *buf;
  215. char    *ap;
  216. {
  217.     register int    cpos;
  218.     register SYMBOL    *sp1;
  219.     register SYMBOL    *sp2;
  220.     register int    i;
  221.     register int    c;
  222.     register int    h;
  223.     register int    nhits;
  224.     register int    nxtra;
  225.     register int    bxtra;
  226.  
  227.     cpos = 0;
  228.     if (kbdmop != NULL) {            /* In a macro.        */
  229.         while ((c = *kbdmop++) != '\0')
  230.             buf[cpos++] = c;
  231.         buf[cpos] = '\0';
  232.         goto done;
  233.     }
  234.     if ((flag&EFNEW)!=0 || ttrow!=nrow-1) {
  235.         ttcolor(CTEXT);
  236.         ttmove(nrow-1, 0);
  237.         epresf = TRUE;
  238.     } else
  239.         eputc(' ');
  240.     eformat(fp, ap);
  241.     tteeol();
  242.     ttflush();
  243.     for (;;) {
  244.         c = ttgetc();
  245.         if (c==' ' && (flag&EFAUTO)!=0) {
  246.             nhits = 0;
  247.             nxtra = HUGE;
  248.             for (h=0; h<NSHASH; ++h) {
  249.                 sp1 = symbol[h];
  250.                 while (sp1 != NULL) {
  251.                     for (i=0; i<cpos; ++i) {
  252.                         if (buf[i] != sp1->s_name[i])
  253.                             break;
  254.                     }
  255.                     if (i == cpos) {
  256.                         if (nhits == 0)
  257.                             sp2 = sp1;
  258.                         ++nhits;
  259.                         bxtra = getxtra(sp1, sp2, cpos);
  260.                         if (bxtra < nxtra)
  261.                             nxtra = bxtra;
  262.                     }
  263.                     sp1 = sp1->s_symp;
  264.                 }
  265.             }
  266.             if (nhits == 0)        /* No completion.    */
  267.                 continue;
  268.             for (i=0; i<nxtra && cpos<nbuf-1; ++i) {
  269.                 c = sp2->s_name[cpos];
  270.                 buf[cpos++] = c;
  271.                 eputc(c);
  272.             }
  273.             ttflush();
  274.             if (nhits != 1)        /* Fake a CR if there    */
  275.                 continue;    /* is 1 choice.        */
  276.             c = 0x0D;
  277.         }
  278.         switch (c) {
  279.         case 0x0D:            /* Return, done.    */
  280.             buf[cpos] = '\0';
  281.             if (kbdmip != NULL) {
  282.                 if (kbdmip+cpos+1 > &kbdm[NKBDM-3]) {
  283.                     (void) ctrlg(FALSE, 0, KRANDOM);
  284.                     ttflush();
  285.                     return (ABORT);
  286.                 }
  287.                 for (i=0; i<cpos; ++i)
  288.                     *kbdmip++ = buf[i];
  289.                 *kbdmip++ = '\0';
  290.             }
  291.             if ((flag&EFCR) != 0) {
  292.                 ttputc(0x0D);
  293.                 ttflush();
  294.             }
  295.             goto done;
  296.  
  297.         case 0x07:            /* Bell, abort.        */
  298.             eputc(0x07);
  299.             (void) ctrlg(FALSE, 0, KRANDOM);
  300.             ttflush();
  301.             return (ABORT);
  302.  
  303.         case 0x7F:            /* Rubout, erase.    */
  304.         case 0x08:            /* Backspace, erase.    */
  305.             if (cpos != 0) {
  306.                 ttputc('\b');
  307.                 ttputc(' ');
  308.                 ttputc('\b');
  309.                 --ttcol;
  310.                 if (ISCTRL(buf[--cpos]) != FALSE) {
  311.                     ttputc('\b');
  312.                     ttputc(' ');
  313.                     ttputc('\b');
  314.                     --ttcol;
  315.                 }
  316.                 ttflush();
  317.             }
  318.             break;
  319.  
  320.         case 0x15:            /* C-U, kill line.    */
  321.             while (cpos != 0) {
  322.                 ttputc('\b');
  323.                 ttputc(' ');
  324.                 ttputc('\b');
  325.                 --ttcol;
  326.                 if (ISCTRL(buf[--cpos]) != FALSE) {
  327.                     ttputc('\b');
  328.                     ttputc(' ');
  329.                     ttputc('\b');
  330.                     --ttcol;
  331.                 }
  332.             }
  333.             ttflush();
  334.             break;
  335.  
  336.         default:            /* All the rest.    */
  337.             if (cpos < nbuf-1) {
  338.                 buf[cpos++] = c;
  339.                 eputc(c);
  340.                 ttflush();
  341.             }
  342.         }
  343.     }
  344. done:
  345.     if (buf[0] == '\0')
  346.         return (FALSE);
  347.     return (TRUE);
  348. }
  349.  
  350. /*
  351.  * The "sp1" and "sp2" point to extended command
  352.  * symbol table entries. The "cpos" is a horizontal position
  353.  * in the name. Return the longest block of characters that can
  354.  * be autocompleted at this point. Sometimes the two symbols
  355.  * are the same, but this is normal.
  356.  */
  357. getxtra(sp1, sp2, cpos)
  358. register SYMBOL    *sp1;
  359. register SYMBOL    *sp2;
  360. {
  361.     register int    i;
  362.  
  363.     i = cpos;
  364.     for (;;) {
  365.         if (sp1->s_name[i] != sp2->s_name[i])
  366.             break;
  367.         if (sp1->s_name[i] == '\0')
  368.             break;
  369.         ++i;
  370.     }
  371.     return (i - cpos);
  372. }
  373.  
  374. /*
  375.  * Special "printf" for the echo line.
  376.  * Each call to "eprintf" starts a new line in the
  377.  * echo area, and ends with an erase to end of the
  378.  * echo line. The formatting is done by a call
  379.  * to the standard formatting routine.
  380.  */
  381. /* VARARGS1 */
  382. eprintf(fp, arg)
  383. char    *fp;
  384. {
  385.     ttcolor(CTEXT);
  386.     ttmove(nrow-1, 0);
  387.     eformat(fp, (char *)&arg);
  388.     tteeol();
  389.     ttflush();
  390.     epresf = TRUE;
  391. }
  392.  
  393. /*
  394.  * Printf style formatting. This is
  395.  * called by both "eprintf" and "ereply", to provide
  396.  * formatting services to their clients. The move to the
  397.  * start of the echo line, and the erase to the end of
  398.  * the echo line, is done by the caller.
  399.  */
  400. eformat(fp, ap)
  401. register char    *fp;
  402. register char    *ap;
  403. {
  404.     register int    c;
  405.  
  406.     while ((c = *fp++) != '\0') {
  407.         if (c != '%')
  408.             eputc(c);
  409.         else {
  410.             c = *fp++;
  411.             switch (c) {
  412.             case 'd':
  413.                 eputi(*(int *)ap, 10);
  414.                 ap += sizeof(int);
  415.                 break;
  416.  
  417.             case 'o':
  418.                 eputi(*(int *)ap,  8);
  419.                 ap += sizeof(int);
  420.                 break;
  421.  
  422.             case 's':
  423.                 eputs(*(char **)ap);
  424.                 ap += sizeof(char *);
  425.                 break;
  426.  
  427.             default:
  428.                 eputc(c);
  429.             }
  430.         }
  431.     }
  432. }
  433.  
  434. /*
  435.  * Put integer, in radix "r".
  436.  */
  437. eputi(i, r)
  438. register int    i;
  439. register int    r;
  440. {
  441.     register int    q;
  442.  
  443.     if ((q=i/r) != 0)
  444.         eputi(q, r);
  445.     eputc(i%r+'0');
  446. }
  447.  
  448. /*
  449.  * Put string.
  450.  */
  451. eputs(s)
  452. register char    *s;
  453. {
  454.     register int    c;
  455.  
  456.     while ((c = *s++) != '\0')
  457.         eputc(c);
  458. }
  459.  
  460. /*
  461.  * Put character. Watch for
  462.  * control characters, and for the line
  463.  * getting too long.
  464.  */
  465. eputc(c)
  466. register int    c;
  467. {
  468.     if (ttcol < ncol) {
  469.         if (ISCTRL(c) != FALSE) {
  470.             eputc('^');
  471.             c ^= 0x40;
  472.         }
  473.         ttputc(c);
  474.         ++ttcol;
  475.     }
  476. }
  477. SHAR_EOF
  478. if test 8844 -ne "`wc -c < 'echo.c'`"
  479. then
  480.     echo shar: error transmitting "'echo.c'" '(should have been 8844 characters)'
  481. fi
  482. fi
  483. echo shar: extracting "'extend.c'" '(3416 characters)'
  484. if test -f 'extend.c'
  485. then
  486.     echo shar: will not over-write existing file "'extend.c'"
  487. else
  488. cat << \SHAR_EOF > 'extend.c'
  489. /*
  490.  * Name:    MicroEMACS
  491.  *        Extended (M-X) commands.
  492.  * Version:    29
  493.  * Last edit:    14-Feb-86
  494.  * By:        rex::conroy
  495.  *        decvax!decwrl!dec-rhea!dec-rex!conroy
  496.  */
  497. #include    "def.h"
  498.  
  499. /*
  500.  * This function modifies the keyboard
  501.  * binding table, by adjusting the entries in the
  502.  * big "bindings" array. Most of the grief deals with the
  503.  * prompting for additional arguments. This code does not
  504.  * work right if there is a keyboard macro floating around.
  505.  * Should be fixed.
  506.  */
  507. bindtokey(f, n, k)
  508. {
  509.     register int    s;
  510.     register char    *cp;
  511.     register SYMBOL    *sp;
  512.     register int    c;
  513.     char        xname[NXNAME];
  514.  
  515.     if (kbdmip!=NULL || kbdmop!=NULL) {
  516.         eprintf("Not now");
  517.         return (FALSE);
  518.     }
  519.     if ((s=eread("Function: ", xname, NXNAME, EFAUTO, NULL)) != TRUE)
  520.         return (s);
  521.     if ((sp=symlookup(xname)) == NULL) {
  522.         eprintf("Unknown function for binding");
  523.         return (FALSE);
  524.     }
  525.     eputc(' ');
  526.     eputc('K');
  527.     eputc('e');
  528.     eputc('y');
  529.     eputc(':');
  530.     eputc(' ');
  531.     ttflush();
  532.     c = getkey();                /* Read key.        */
  533.     keyname(xname, c);            /* Display keyname.    */
  534.     eputs(xname);
  535.     ttflush();
  536.     if (binding[c] != NULL)            /* Unbind old, and    */
  537.         --binding[c]->s_nkey;
  538.     binding[c] = sp;            /* rebind new.        */
  539.     ++sp->s_nkey;
  540.     return (TRUE);
  541. }
  542.  
  543. /*
  544.  * Extended command. Call the message line
  545.  * routine to read in the command name and apply autocompletion
  546.  * to it. When it comes back, look the name up in the symbol table
  547.  * and run the command if it is found and has the right type.
  548.  * Print an error if there is anything wrong.
  549.  */
  550. extend(f, n, k)
  551. {
  552.     register SYMBOL    *sp;
  553.     register int    s;
  554.     char        xname[NXNAME];
  555.  
  556.     if ((s=eread(": ", xname, NXNAME, EFNEW|EFAUTO, NULL)) != TRUE)
  557.         return (s);
  558.     if ((sp=symlookup(xname)) != NULL)
  559.         return ((*sp->s_funcp)(f, n, KRANDOM));
  560.     eprintf("Unknown extended command");
  561.     return (ABORT);
  562. }
  563.  
  564. /*
  565.  * Read a key from the keyboard, and look it
  566.  * up in the binding table. Display the name of the function
  567.  * currently bound to the key. Say that the key is not bound
  568.  * if it is indeed not bound, or if the type is not a
  569.  * "builtin". This is a bit of overkill, because this is the
  570.  * only kind of function there is.
  571.  */
  572. help(f, n, k)
  573. {
  574.     register SYMBOL    *sp;
  575.     register int    c;
  576.     char        b[20];
  577.  
  578.     c = getkey();
  579.     keyname(b, c);
  580.     if ((sp=binding[c]) == NULL)
  581.         eprintf("[%s is unbound]", b);
  582.     else
  583.         eprintf("[%s is bound to %s]", b, sp->s_name);
  584.     return (TRUE);
  585. }
  586.  
  587. /*
  588.  * This function creates a table, listing all
  589.  * of the command keys and their current bindings, and stores
  590.  * the table in the standard pop-op buffer (the one used by the
  591.  * directory list command, the buffer list command, etc.). This
  592.  * lets MicroEMACS produce it's own wall chart. The bindings to
  593.  * "ins-self" are only displayed if there is an argument.
  594.  */
  595. wallchart(f, n, k)
  596. {
  597.     register int    s;
  598.     register int    key;
  599.     register SYMBOL    *sp;
  600.     register char    *cp1;
  601.     register char    *cp2;
  602.     char        buf[64];
  603.  
  604.     if ((s=bclear(blistp)) != TRUE)        /* Clear it out.    */
  605.         return (s);
  606.     (void) strcpy(blistp->b_fname, "");
  607.     for (key=0; key<NKEYS; ++key) {        /* For all keys.    */
  608.         sp = binding[key];
  609.         if (sp != NULL
  610.         && (f!=FALSE || strcmp(sp->s_name, "ins-self")!=0)) {
  611.             keyname(buf, key);
  612.             cp1 = &buf[0];        /* Find end.        */
  613.             while (*cp1 != 0)
  614.                 ++cp1;
  615.             while (cp1 < &buf[16])    /* Goto column 16.    */
  616.                 *cp1++ = ' ';                
  617.             cp2 = sp->s_name;    /* Add function name.    */
  618.             while (*cp1++ = *cp2++)
  619.                 ;
  620.             if (addline(buf) == FALSE)
  621.                 return (FALSE);
  622.         }
  623.     }
  624.     return (popblist());
  625. }
  626. SHAR_EOF
  627. if test 3416 -ne "`wc -c < 'extend.c'`"
  628. then
  629.     echo shar: error transmitting "'extend.c'" '(should have been 3416 characters)'
  630. fi
  631. fi
  632. echo shar: extracting "'file.c'" '(9404 characters)'
  633. if test -f 'file.c'
  634. then
  635.     echo shar: will not over-write existing file "'file.c'"
  636. else
  637. cat << \SHAR_EOF > 'file.c'
  638. /*
  639.  * Name:    MicroEMACS
  640.  *         File commands.
  641.  * Version:    29
  642.  * Last edit:    05-Feb-86
  643.  * By:        rex::conroy
  644.  *        decvax!decwrl!dec-rhea!dec-rex!conroy
  645.  */
  646. #include    "def.h"
  647.  
  648. /*
  649.  * Read a file into the current
  650.  * buffer. This is really easy; all you do it
  651.  * find the name of the file, and call the standard
  652.  * "read a file into the current buffer" code.
  653.  */
  654. fileread(f, n, k)
  655. {
  656.     register int    s;
  657.     char        fname[NFILEN];
  658.  
  659.     if ((s=ereply("Read file: ", fname, NFILEN)) != TRUE)
  660.         return (s);
  661.     adjustcase(fname);
  662.     return (readin(fname));
  663. }
  664.  
  665. /*
  666.  * Select a file for editing.
  667.  * Look around to see if you can find the
  668.  * fine in another buffer; if you can find it
  669.  * just switch to the buffer. If you cannot find
  670.  * the file, create a new buffer, read in the
  671.  * text, and switch to the new buffer.
  672.  */
  673. filevisit(f, n, k)
  674. {
  675.     register BUFFER    *bp;
  676.     register WINDOW    *wp;
  677.     register LINE    *lp;
  678.     register int    i;
  679.     register int    s;
  680.     char        bname[NBUFN];
  681.     char        fname[NFILEN];
  682.  
  683.     if ((s=ereply("Visit file: ", fname, NFILEN)) != TRUE)
  684.         return (s);
  685.     adjustcase(fname);
  686.     for (bp=bheadp; bp!=NULL; bp=bp->b_bufp) {
  687.         if (strcmp(bp->b_fname, fname) == 0) {
  688.             if (--curbp->b_nwnd == 0) {
  689.                 curbp->b_dotp  = curwp->w_dotp;
  690.                 curbp->b_doto  = curwp->w_doto;
  691.                 curbp->b_markp = curwp->w_markp;
  692.                 curbp->b_marko = curwp->w_marko;
  693.             }
  694.             curbp = bp;
  695.             curwp->w_bufp  = bp;
  696.             if (bp->b_nwnd++ == 0) {
  697.                 curwp->w_dotp  = bp->b_dotp;
  698.                 curwp->w_doto  = bp->b_doto;
  699.                 curwp->w_markp = bp->b_markp;
  700.                 curwp->w_marko = bp->b_marko;
  701.             } else {
  702.                 wp = wheadp;
  703.                 while (wp != NULL) {
  704.                     if (wp!=curwp && wp->w_bufp==bp) {
  705.                         curwp->w_dotp  = wp->w_dotp;
  706.                         curwp->w_doto  = wp->w_doto;
  707.                         curwp->w_markp = wp->w_markp;
  708.                         curwp->w_marko = wp->w_marko;
  709.                         break;
  710.                     }
  711.                     wp = wp->w_wndp;
  712.                 }
  713.             }
  714.             lp = curwp->w_dotp;
  715.             i = curwp->w_ntrows/2;
  716.             while (i-- && lback(lp)!=curbp->b_linep)
  717.                 lp = lback(lp);
  718.             curwp->w_linep = lp;
  719.             curwp->w_flag |= WFMODE|WFHARD;
  720.             if (kbdmop == NULL)
  721.                 eprintf("[Old buffer]");
  722.             return (TRUE);
  723.         }
  724.     }
  725.     makename(bname, fname);            /* New buffer name.    */
  726.     while ((bp=bfind(bname, FALSE)) != NULL) {
  727.         s = ereply("Buffer name: ", bname, NBUFN);
  728.         if (s == ABORT)            /* ^G to just quit    */
  729.             return (s);
  730.         if (s == FALSE) {        /* CR to clobber it    */
  731.             makename(bname, fname);
  732.             break;
  733.         }
  734.     }
  735.     if (bp==NULL && (bp=bfind(bname, TRUE))==NULL) {
  736.         eprintf("Cannot create buffer");
  737.         return (FALSE);
  738.     }
  739.     if (--curbp->b_nwnd == 0) {        /* Undisplay.        */
  740.         curbp->b_dotp = curwp->w_dotp;
  741.         curbp->b_doto = curwp->w_doto;
  742.         curbp->b_markp = curwp->w_markp;
  743.         curbp->b_marko = curwp->w_marko;
  744.     }
  745.     curbp = bp;                /* Switch to it.    */
  746.     curwp->w_bufp = bp;
  747.     curbp->b_nwnd++;
  748.     return (readin(fname));            /* Read it in.        */
  749. }
  750.  
  751. /*
  752.  * Read the file "fname" into the current buffer.
  753.  * Make all of the text in the buffer go away, after checking
  754.  * for unsaved changes. This is called by the "read" command, the
  755.  * "visit" command, and the mainline (for "uemacs file"). If the
  756.  * BACKUP conditional is set, then this routine also does the read
  757.  * end of backup processing. The BFBAK flag, if set in a buffer,
  758.  * says that a backup should be taken. It is set when a file is
  759.  * read in, but not on a new file (you don't need to make a backup
  760.  * copy of nothing). Return a standard status. Print a summary
  761.  * (lines read, error message) out as well.
  762.  */
  763. readin(fname)
  764. char    fname[];
  765. {
  766.     register LINE    *lp1;
  767.     register LINE    *lp2;
  768.     register int    i;
  769.     register WINDOW    *wp;
  770.     register BUFFER    *bp;
  771.     register int    s;
  772.     register int    nbytes;
  773.     register int    nline;
  774.     char        line[NLINE];
  775.  
  776.     bp = curbp;                /* Cheap.        */
  777.     if ((s=bclear(bp)) != TRUE)        /* Might be old.    */
  778.         return (s);
  779. #if    BACKUP
  780.     bp->b_flag &= ~(BFCHG|BFBAK);        /* No change, backup.    */
  781. #else
  782.     bp->b_flag &= ~BFCHG;            /* No change.        */
  783. #endif
  784.     strcpy(bp->b_fname, fname);
  785.     if ((s=ffropen(fname)) == FIOERR)     /* Hard file open.    */
  786.         goto out;
  787.     if (s == FIOFNF) {            /* File not found.    */
  788.         if (kbdmop == NULL)
  789.             eprintf("[New file]");
  790.         goto out;
  791.     }
  792.     nline = 0;
  793.     while ((s=ffgetline(line, NLINE)) == FIOSUC) {
  794.         nbytes = strlen(line);
  795.         if ((lp1=lalloc(nbytes)) == NULL) {
  796.             s = FIOERR;        /* Keep message on the    */
  797.             break;            /* display.        */
  798.         }
  799.         lp2 = lback(curbp->b_linep);
  800.         lp2->l_fp = lp1;
  801.         lp1->l_fp = curbp->b_linep;
  802.         lp1->l_bp = lp2;
  803.         curbp->b_linep->l_bp = lp1;
  804.         for (i=0; i<nbytes; ++i)
  805.             lputc(lp1, i, line[i]);
  806.         ++nline;
  807.     }
  808.     ffclose();                /* Ignore errors.    */
  809.     if (s==FIOEOF && kbdmop==NULL) {    /* Don't zap an error.    */
  810.         if (nline == 1)
  811.             eprintf("[Read 1 line]");
  812.         else
  813.             eprintf("[Read %d lines]", nline);
  814.     }
  815. #if    BACKUP
  816.     curbp->b_flag |= BFBAK;            /* Need a backup.    */
  817. #endif
  818. out:
  819.     for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
  820.         if (wp->w_bufp == curbp) {
  821.             wp->w_linep = lforw(curbp->b_linep);
  822.             wp->w_dotp  = lforw(curbp->b_linep);
  823.             wp->w_doto  = 0;
  824.             wp->w_markp = NULL;
  825.             wp->w_marko = 0;
  826.             wp->w_flag |= WFMODE|WFHARD;
  827.         }
  828.     }
  829.     if (s == FIOERR)            /* False if error.    */
  830.         return (FALSE);
  831.     return (TRUE);
  832. }
  833.  
  834. /*
  835.  * Take a file name, and from it
  836.  * fabricate a buffer name. This routine knows
  837.  * about the syntax of file names on the target system.
  838.  * BDC1        left scan delimiter.
  839.  * BDC2        optional second left scan delimiter.
  840.  * BDC3        optional right scan delimiter.
  841.  */
  842. makename(bname, fname)
  843. char    bname[];
  844. char    fname[];
  845. {
  846.     register char    *cp1;
  847.     register char    *cp2;
  848.  
  849.     cp1 = &fname[0];
  850.     while (*cp1 != 0)
  851.         ++cp1;
  852. #ifdef    BDC2
  853.     while (cp1!=&fname[0] && cp1[-1]!=BDC1 && cp1[-1]!=BDC2)
  854.         --cp1;
  855. #else
  856.     while (cp1!=&fname[0] && cp1[-1]!=BDC1)
  857.         --cp1;
  858. #endif
  859.     cp2 = &bname[0];
  860. #ifdef    BDC3
  861.     while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=BDC3)
  862.         *cp2++ = *cp1++;
  863. #else
  864.     while (cp2!=&bname[NBUFN-1] && *cp1!=0)
  865.         *cp2++ = *cp1++;
  866. #endif
  867.     *cp2 = 0;
  868. }
  869.  
  870. /*
  871.  * Ask for a file name, and write the
  872.  * contents of the current buffer to that file.
  873.  * Update the remembered file name and clear the
  874.  * buffer changed flag. This handling of file names
  875.  * is different from the earlier versions, and
  876.  * is more compatable with Gosling EMACS than
  877.  * with ITS EMACS.
  878.  */
  879. filewrite(f, n, k)
  880. {
  881.     register WINDOW    *wp;
  882.     register int    s;
  883.     char        fname[NFILEN];
  884.  
  885.     if ((s=ereply("Write file: ", fname, NFILEN)) != TRUE)
  886.         return (s);
  887.     adjustcase(fname);
  888.     if ((s=writeout(fname)) == TRUE) {
  889.         strcpy(curbp->b_fname, fname);
  890.         curbp->b_flag &= ~BFCHG;
  891.         wp = wheadp;            /* Update mode lines.    */
  892.         while (wp != NULL) {
  893.             if (wp->w_bufp == curbp)
  894.                 wp->w_flag |= WFMODE;
  895.             wp = wp->w_wndp;
  896.         }
  897.     }
  898. #if    BACKUP
  899.     curbp->b_flag &= ~BFBAK;        /* No backup.        */
  900. #endif
  901.     return (s);
  902. }
  903.  
  904. /*
  905.  * Save the contents of the current buffer back into
  906.  * its associated file. Do nothing if there have been no changes
  907.  * (is this a bug, or a feature). Error if there is no remembered
  908.  * file name. If this is the first write since the read or visit,
  909.  * then a backup copy of the file is made.
  910.  */
  911. filesave(f, n, k)
  912. {
  913.     register WINDOW    *wp;
  914.     register int    s;
  915.  
  916.     if ((curbp->b_flag&BFCHG) == 0)        /* Return, no changes.    */
  917.         return (TRUE);
  918.     if (curbp->b_fname[0] == 0) {        /* Must have a name.    */
  919.         eprintf("No file name");
  920.         return (FALSE);
  921.     }
  922. #if    BACKUP
  923.     if ((curbp->b_flag&BFBAK) != 0) {
  924.         s = fbackupfile(curbp->b_fname);
  925.         if (s == ABORT)            /* Hard error.        */
  926.             return (s);
  927.         if (s == FALSE            /* Softer error.    */
  928.         && (s=eyesno("Backup error, save anyway")) != TRUE)
  929.             return (s);
  930.     }
  931. #endif
  932.     if ((s=writeout(curbp->b_fname)) == TRUE) {
  933.         curbp->b_flag &= ~BFCHG;
  934.         wp = wheadp;            /* Update mode lines.    */
  935.         while (wp != NULL) {
  936.             if (wp->w_bufp == curbp)
  937.                 wp->w_flag |= WFMODE;
  938.             wp = wp->w_wndp;
  939.         }
  940.     }
  941. #if    BACKUP
  942.     curbp->b_flag &= ~BFBAK;        /* No backup.        */
  943. #endif
  944.     return (s);
  945. }
  946.  
  947. /*
  948.  * This function performs the details of file
  949.  * writing. Uses the file management routines in the
  950.  * "fileio.c" package. The number of lines written is
  951.  * displayed. Sadly, it looks inside a LINE; provide
  952.  * a macro for this. Most of the grief is error
  953.  * checking of some sort.
  954.  */
  955. writeout(fn)
  956. char    *fn;
  957. {
  958.     register int    s;
  959.     register LINE    *lp;
  960.     register int    nline;
  961.  
  962.     if ((s=ffwopen(fn)) != FIOSUC)        /* Open writes message.    */
  963.         return (FALSE);
  964.     lp = lforw(curbp->b_linep);        /* First line.        */
  965.     nline = 0;                /* Number of lines.    */
  966.     while (lp != curbp->b_linep) {
  967.         if ((s=ffputline(&lp->l_text[0], llength(lp))) != FIOSUC)
  968.             break;
  969.         ++nline;
  970.         lp = lforw(lp);
  971.     }
  972.     if (s == FIOSUC) {            /* No write error.    */
  973.         s = ffclose();
  974.         if (s==FIOSUC && kbdmop==NULL) {
  975.             if (nline == 1)
  976.                 eprintf("[Wrote 1 line]");
  977.             else
  978.                 eprintf("[Wrote %d lines]", nline);
  979.         }
  980.     } else                    /* Ignore close error    */
  981.         ffclose();            /* if a write error.    */
  982.     if (s != FIOSUC)            /* Some sort of error.    */
  983.         return (FALSE);
  984.     return (TRUE);
  985. }
  986.  
  987. /*
  988.  * The command allows the user
  989.  * to modify the file name associated with
  990.  * the current buffer. It is like the "f" command
  991.  * in UNIX "ed". The operation is simple; just zap
  992.  * the name in the BUFFER structure, and mark the windows
  993.  * as needing an update. You can type a blank line at the
  994.  * prompt if you wish.
  995.  */
  996. filename(f, n, k)
  997. {
  998.     register WINDOW    *wp;
  999.     register int    s;
  1000.     char         fname[NFILEN];
  1001.  
  1002.     if ((s=ereply("Name: ", fname, NFILEN)) == ABORT)
  1003.         return (s);
  1004.     adjustcase(fname);
  1005.     strcpy(curbp->b_fname, fname);        /* Fix name.        */
  1006.     wp = wheadp;                /* Update mode lines.    */
  1007.     while (wp != NULL) {
  1008.         if (wp->w_bufp == curbp)
  1009.             wp->w_flag |= WFMODE;
  1010.         wp = wp->w_wndp;
  1011.     }
  1012. #if    BACKUP
  1013.     curbp->b_flag &= ~BFBAK;        /* No backup.        */
  1014. #endif
  1015.     return (TRUE);
  1016. }
  1017. SHAR_EOF
  1018. if test 9404 -ne "`wc -c < 'file.c'`"
  1019. then
  1020.     echo shar: error transmitting "'file.c'" '(should have been 9404 characters)'
  1021. fi
  1022. fi
  1023. echo shar: extracting "'kbd.c'" '(2689 characters)'
  1024. if test -f 'kbd.c'
  1025. then
  1026.     echo shar: will not over-write existing file "'kbd.c'"
  1027. else
  1028. cat << \SHAR_EOF > 'kbd.c'
  1029. /*
  1030.  * Name:    MicroEMACS
  1031.  *        Terminal independent keyboard handling.
  1032.  * Version:    29
  1033.  * Last edit:    05-Feb-86
  1034.  * By:        rex::conroy
  1035.  *        decvax!decwrl!dec-rhea!dec-rex!conroy
  1036.  */
  1037. #include    "def.h"
  1038.  
  1039. /*
  1040.  * Read in a key, doing the terminal
  1041.  * independent prefix handling. The terminal specific
  1042.  * "getkbd" routine gets the first swing, and may return
  1043.  * one of the special codes used by the special keys
  1044.  * on the keyboard. The "getkbd" routine returns the
  1045.  * C0 controls as received; this routine moves them to
  1046.  * the right spot in 11 bit code.
  1047.  */
  1048. getkey()
  1049. {
  1050.     register int    c;
  1051.  
  1052.     c = getkbd();
  1053.     if (c == METACH)            /* M-            */
  1054.         c = KMETA | getctl();
  1055.     else if (c == CTRLCH)            /* C-            */
  1056.         c = KCTRL | getctl();
  1057.     else if (c == CTMECH)            /* C-M-            */
  1058.         c = KCTRL | KMETA | getctl();
  1059.     else if (c>=0x00 && c<=0x1F)        /* Relocate control.    */
  1060.         c = KCTRL | (c+'@');
  1061.     if (c == (KCTRL|'X'))            /* C-X            */
  1062.         c = KCTLX | getctl();
  1063.     return (c);
  1064. }
  1065.  
  1066. /*
  1067.  * Used above.
  1068.  */
  1069. getctl()
  1070. {
  1071.     register int    c;
  1072.  
  1073.     c = ttgetc();
  1074.     if (ISLOWER(c) != FALSE)
  1075.         c = TOUPPER(c);
  1076.     if (c>=0x00 && c<=0x1F)            /* Relocate control.    */
  1077.         c = KCTRL | (c+'@');
  1078.     return (c);
  1079. }
  1080.  
  1081. /*
  1082.  * Transform a key code into a name,
  1083.  * using a table for the special keys and combination
  1084.  * of some hard code and some general processing for
  1085.  * the rest. None of this code is terminal specific any
  1086.  * more. This makes adding keys easier.
  1087.  */
  1088. keyname(cp, k)
  1089. register char    *cp;
  1090. register int    k;
  1091. {
  1092.     register char    *np;
  1093.     char        nbuf[3];
  1094.  
  1095.     static    char    hex[] = {
  1096.         '0',    '1',    '2',    '3',
  1097.         '4',    '5',    '6',    '7',
  1098.         '8',    '9',    'A',    'B',
  1099.         'C',    'D',    'E',    'F'
  1100.     };
  1101.  
  1102.     if ((k&KCTLX) != 0) {            /* C-X prefix.        */
  1103.         *cp++ = 'C';
  1104.         *cp++ = '-';
  1105.         *cp++ = 'X';
  1106.         *cp++ = ' ';
  1107.         k &= ~KCTLX;
  1108.     }
  1109.     if ((k&KCHAR)>=KFIRST && (k&KCHAR)<=KLAST) {
  1110.         if ((np=keystrings[(k&KCHAR)-KFIRST]) != NULL) {
  1111.             if ((k&KCTRL) != 0) {
  1112.                 *cp++ = 'C';
  1113.                 *cp++ = '-';
  1114.             }
  1115.             if ((k&KMETA) != 0) {
  1116.                 *cp++ = 'M';
  1117.                 *cp++ = '-';
  1118.             }
  1119.             strcpy(cp, np);
  1120.             return;
  1121.         }
  1122.     }
  1123.     if ((k&~KMETA) == (KCTRL|'I'))        /* Some specials.    */
  1124.         np = "Tab";
  1125.     else if ((k&~KMETA) == (KCTRL|'M'))
  1126.         np = "Return";
  1127.     else if ((k&~KMETA) == (KCTRL|'H'))
  1128.         np = "Backspace";
  1129.     else if ((k&~KMETA) == ' ')
  1130.         np = "Space";
  1131.     else if ((k&~KMETA) == 0x7F)
  1132.         np = "Rubout";
  1133.     else {
  1134.         if ((k&KCTRL) != 0) {        /* Add C- mark.        */
  1135.             *cp++ = 'C';
  1136.             *cp++ = '-';
  1137.         }
  1138.         np = &nbuf[0];
  1139.         if (((k&KCHAR)>=0x20 && (k&KCHAR)<=0x7E)
  1140.         ||  ((k&KCHAR)>=0xA0 && (k&KCHAR)<=0xFE)) {
  1141.             nbuf[0] = k&KCHAR;    /* Graphic.        */
  1142.             nbuf[1] = 0;
  1143.         } else {            /* Non graphic.        */
  1144.             nbuf[0] = hex[(k>>4)&0x0F];
  1145.             nbuf[1] = hex[k&0x0F];
  1146.             nbuf[2] = 0;
  1147.         }
  1148.     }
  1149.     if ((k&KMETA) != 0) {            /* Add M- mark.        */
  1150.         *cp++ = 'M';
  1151.         *cp++ = '-';
  1152.     }
  1153.     strcpy(cp, np);
  1154. }
  1155. SHAR_EOF
  1156. if test 2689 -ne "`wc -c < 'kbd.c'`"
  1157. then
  1158.     echo shar: error transmitting "'kbd.c'" '(should have been 2689 characters)'
  1159. fi
  1160. fi
  1161. echo shar: extracting "'line.c'" '(14554 characters)'
  1162. if test -f 'line.c'
  1163. then
  1164.     echo shar: will not over-write existing file "'line.c'"
  1165. else
  1166. cat << \SHAR_EOF > 'line.c'
  1167. /*
  1168.  * Name:    MicroEMACS
  1169.  *        Text line handling.
  1170.  * Version:    29
  1171.  * Last edit:    14-Feb-86
  1172.  * By:        rex::conroy, vox::ellison
  1173.  *        decvax!decwrl!dec-rhea!dec-rex!conroy
  1174.  *                   ...!dec-vox!ellison
  1175.  *
  1176.  * The functions in this file
  1177.  * are a general set of line management
  1178.  * utilities. They are the only routines that
  1179.  * touch the text. They also touch the buffer
  1180.  * and window structures, to make sure that the
  1181.  * necessary updating gets done. There are routines
  1182.  * in this file that handle the kill buffer too.
  1183.  * It isn't here for any good reason.
  1184.  *
  1185.  * Note that this code only updates the dot and
  1186.  * mark values in the window list. Since all the code
  1187.  * acts on the current window, the buffer that we
  1188.  * are editing must be being displayed, which means
  1189.  * that "b_nwnd" is non zero, which means that the
  1190.  * dot and mark values in the buffer headers are
  1191.  * nonsense.
  1192.  */
  1193. #include    "def.h"
  1194.  
  1195. #define    NBLOCK    16            /* Line block chunk size    */
  1196.  
  1197. #ifndef    KBLOCK
  1198. #define    KBLOCK    256            /* Kill buffer block size.    */
  1199. #endif
  1200.  
  1201. char    *kbufp    = NULL;            /* Kill buffer data.        */
  1202. int    kused    = 0;            /* # of bytes used in KB.    */
  1203. int    ksize    = 0;            /* # of bytes allocated in KB.    */
  1204.  
  1205. /*
  1206.  * This routine allocates a block
  1207.  * of memory large enough to hold a LINE
  1208.  * containing "used" characters. The block is
  1209.  * always rounded up a bit. Return a pointer
  1210.  * to the new block, or NULL if there isn't
  1211.  * any memory left. Print a message in the
  1212.  * message line if no space.
  1213.  */
  1214. LINE    *
  1215. lalloc(used)
  1216. register int    used;
  1217. {
  1218.     register LINE    *lp;
  1219.     register int    size;
  1220.  
  1221.     size = (used+NBLOCK-1) & ~(NBLOCK-1);
  1222.     if (size == 0)                /* Assume that an empty    */
  1223.         size = NBLOCK;            /* line is for type-in.    */
  1224.     if ((lp=(LINE *)malloc(sizeof(LINE)+size)) == NULL) {
  1225.         eprintf("Cannot allocate %d bytes", size);
  1226.         return (NULL);
  1227.     }
  1228.     lp->l_size = size;
  1229.     lp->l_used = used;
  1230.     return (lp);
  1231. }
  1232.  
  1233. /*
  1234.  * Delete line "lp". Fix all of the
  1235.  * links that might point at it (they are
  1236.  * moved to offset 0 of the next line.
  1237.  * Unlink the line from whatever buffer it
  1238.  * might be in. Release the memory. The
  1239.  * buffers are updated too; the magic conditions
  1240.  * described in the above comments don't hold
  1241.  * here.
  1242.  */
  1243. lfree(lp)
  1244. register LINE    *lp;
  1245. {
  1246.     register BUFFER    *bp;
  1247.     register WINDOW    *wp;
  1248.  
  1249.     wp = wheadp;
  1250.     while (wp != NULL) {
  1251.         if (wp->w_linep == lp)
  1252.             wp->w_linep = lp->l_fp;
  1253.         if (wp->w_dotp  == lp) {
  1254.             wp->w_dotp  = lp->l_fp;
  1255.             wp->w_doto  = 0;
  1256.         }
  1257.         if (wp->w_markp == lp) {
  1258.             wp->w_markp = lp->l_fp;
  1259.             wp->w_marko = 0;
  1260.         }
  1261.         wp = wp->w_wndp;
  1262.     }
  1263.     bp = bheadp;
  1264.     while (bp != NULL) {
  1265.         if (bp->b_nwnd == 0) {
  1266.             if (bp->b_dotp  == lp) {
  1267.                 bp->b_dotp = lp->l_fp;
  1268.                 bp->b_doto = 0;
  1269.             }
  1270.             if (bp->b_markp == lp) {
  1271.                 bp->b_markp = lp->l_fp;
  1272.                 bp->b_marko = 0;
  1273.             }
  1274.         }
  1275.         bp = bp->b_bufp;
  1276.     }
  1277.     lp->l_bp->l_fp = lp->l_fp;
  1278.     lp->l_fp->l_bp = lp->l_bp;
  1279.     free((char *) lp);
  1280. }
  1281.  
  1282. /*
  1283.  * This routine gets called when
  1284.  * a character is changed in place in the
  1285.  * current buffer. It updates all of the required
  1286.  * flags in the buffer and window system. The flag
  1287.  * used is passed as an argument; if the buffer is being
  1288.  * displayed in more than 1 window we change EDIT to
  1289.  * HARD. Set MODE if the mode line needs to be
  1290.  * updated (the "*" has to be set).
  1291.  */
  1292. lchange(flag)
  1293. register int    flag;
  1294. {
  1295.     register WINDOW    *wp;
  1296.  
  1297.     if (curbp->b_nwnd != 1)            /* Ensure hard.        */
  1298.         flag = WFHARD;
  1299.     if ((curbp->b_flag&BFCHG) == 0) {    /* First change, so     */
  1300.         flag |= WFMODE;            /* update mode lines.    */
  1301.         curbp->b_flag |= BFCHG;
  1302.     }
  1303.     wp = wheadp;
  1304.     while (wp != NULL) {
  1305.         if (wp->w_bufp == curbp)
  1306.             wp->w_flag |= flag;
  1307.         wp = wp->w_wndp;
  1308.     }
  1309. }
  1310.  
  1311. /*
  1312.  * Insert "n" copies of the character "c"
  1313.  * at the current location of dot. In the easy case
  1314.  * all that happens is the text is stored in the line.
  1315.  * In the hard case, the line has to be reallocated.
  1316.  * When the window list is updated, take special
  1317.  * care; I screwed it up once. You always update dot
  1318.  * in the current window. You update mark, and a
  1319.  * dot in another window, if it is greater than
  1320.  * the place where you did the insert. Return TRUE
  1321.  * if all is well, and FALSE on errors.
  1322.  */
  1323. linsert(n, c)
  1324. {
  1325.     register char    *cp1;
  1326.     register char    *cp2;
  1327.     register LINE    *lp1;
  1328.     register LINE    *lp2;
  1329.     register LINE    *lp3;
  1330.     register int    doto;
  1331.     register int    i;
  1332.     register WINDOW    *wp;
  1333.  
  1334.     lchange(WFEDIT);
  1335.     lp1 = curwp->w_dotp;            /* Current line        */
  1336.     if (lp1 == curbp->b_linep) {        /* At the end: special    */
  1337.         if (curwp->w_doto != 0) {
  1338.             eprintf("bug: linsert");
  1339.             return (FALSE);
  1340.         }
  1341.         if ((lp2=lalloc(n)) == NULL)    /* Allocate new line    */
  1342.             return (FALSE);
  1343.         lp3 = lp1->l_bp;        /* Previous line    */
  1344.         lp3->l_fp = lp2;        /* Link in        */
  1345.         lp2->l_fp = lp1;
  1346.         lp1->l_bp = lp2;
  1347.         lp2->l_bp = lp3;
  1348.         for (i=0; i<n; ++i)
  1349.             lp2->l_text[i] = c;
  1350.         curwp->w_dotp = lp2;
  1351.         curwp->w_doto = n;
  1352.         return (TRUE);
  1353.     }
  1354.     doto = curwp->w_doto;            /* Save for later.    */
  1355.     if (lp1->l_used+n > lp1->l_size) {    /* Hard: reallocate    */
  1356.         if ((lp2=lalloc(lp1->l_used+n)) == NULL)
  1357.             return (FALSE);
  1358.         cp1 = &lp1->l_text[0];
  1359.         cp2 = &lp2->l_text[0];
  1360.         while (cp1 != &lp1->l_text[doto])
  1361.             *cp2++ = *cp1++;
  1362.         cp2 += n;
  1363.         while (cp1 != &lp1->l_text[lp1->l_used])
  1364.             *cp2++ = *cp1++;
  1365.         lp1->l_bp->l_fp = lp2;
  1366.         lp2->l_fp = lp1->l_fp;
  1367.         lp1->l_fp->l_bp = lp2;
  1368.         lp2->l_bp = lp1->l_bp;
  1369.         free((char *) lp1);
  1370.     } else {                /* Easy: in place    */
  1371.         lp2 = lp1;            /* Pretend new line    */
  1372.         lp2->l_used += n;
  1373.         cp2 = &lp1->l_text[lp1->l_used];
  1374.         cp1 = cp2-n;
  1375.         while (cp1 != &lp1->l_text[doto])
  1376.             *--cp2 = *--cp1;
  1377.     }
  1378.     for (i=0; i<n; ++i)            /* Add the characters    */
  1379.         lp2->l_text[doto+i] = c;
  1380.     wp = wheadp;                /* Update windows    */
  1381.     while (wp != NULL) {
  1382.         if (wp->w_linep == lp1)
  1383.             wp->w_linep = lp2;
  1384.         if (wp->w_dotp == lp1) {
  1385.             wp->w_dotp = lp2;
  1386.             if (wp==curwp || wp->w_doto>doto)
  1387.                 wp->w_doto += n;
  1388.         }
  1389.         if (wp->w_markp == lp1) {
  1390.             wp->w_markp = lp2;
  1391.             if (wp->w_marko > doto)
  1392.                 wp->w_marko += n;
  1393.         }
  1394.         wp = wp->w_wndp;
  1395.     }
  1396.     return (TRUE);
  1397. }
  1398.  
  1399. /*
  1400.  * Insert a newline into the buffer
  1401.  * at the current location of dot in the current
  1402.  * window. The funny ass-backwards way it does things
  1403.  * is not a botch; it just makes the last line in
  1404.  * the file not a special case. Return TRUE if everything
  1405.  * works out and FALSE on error (memory allocation
  1406.  * failure). The update of dot and mark is a bit
  1407.  * easier then in the above case, because the split
  1408.  * forces more updating.
  1409.  */
  1410. lnewline()
  1411. {
  1412.     register char    *cp1;
  1413.     register char    *cp2;
  1414.     register LINE    *lp1;
  1415.     register LINE    *lp2;
  1416.     register int    doto;
  1417.     register WINDOW    *wp;
  1418.  
  1419.     lchange(WFHARD);
  1420.     lp1  = curwp->w_dotp;            /* Get the address and    */
  1421.     doto = curwp->w_doto;            /* offset of "."    */
  1422.     if ((lp2=lalloc(doto)) == NULL)        /* New first half line    */
  1423.         return (FALSE);
  1424.     cp1 = &lp1->l_text[0];            /* Shuffle text around    */
  1425.     cp2 = &lp2->l_text[0];
  1426.     while (cp1 != &lp1->l_text[doto])
  1427.         *cp2++ = *cp1++;
  1428.     cp2 = &lp1->l_text[0];
  1429.     while (cp1 != &lp1->l_text[lp1->l_used])
  1430.         *cp2++ = *cp1++;
  1431.     lp1->l_used -= doto;
  1432.     lp2->l_bp = lp1->l_bp;
  1433.     lp1->l_bp = lp2;
  1434.     lp2->l_bp->l_fp = lp2;
  1435.     lp2->l_fp = lp1;
  1436.     wp = wheadp;                /* Windows        */
  1437.     while (wp != NULL) {
  1438.         if (wp->w_linep == lp1)
  1439.             wp->w_linep = lp2;
  1440.         if (wp->w_dotp == lp1) {
  1441.             if (wp->w_doto < doto)
  1442.                 wp->w_dotp = lp2;
  1443.             else
  1444.                 wp->w_doto -= doto;
  1445.         }
  1446.         if (wp->w_markp == lp1) {
  1447.             if (wp->w_marko < doto)
  1448.                 wp->w_markp = lp2;
  1449.             else
  1450.                 wp->w_marko -= doto;
  1451.         }
  1452.         wp = wp->w_wndp;
  1453.     }    
  1454.     return (TRUE);
  1455. }
  1456.  
  1457. /*
  1458.  * This function deletes "n" bytes,
  1459.  * starting at dot. It understands how do deal
  1460.  * with end of lines, etc. It returns TRUE if all
  1461.  * of the characters were deleted, and FALSE if
  1462.  * they were not (because dot ran into the end of
  1463.  * the buffer. The "kflag" is TRUE if the text
  1464.  * should be put in the kill buffer.
  1465.  */
  1466. ldelete(n, kflag)
  1467. {
  1468.     register char    *cp1;
  1469.     register char    *cp2;
  1470.     register LINE    *dotp;
  1471.     register int    doto;
  1472.     register int    chunk;
  1473.     register WINDOW    *wp;
  1474.  
  1475.     while (n != 0) {
  1476.         dotp = curwp->w_dotp;
  1477.         doto = curwp->w_doto;
  1478.         if (dotp == curbp->b_linep)    /* Hit end of buffer.    */
  1479.             return (FALSE);
  1480.         chunk = dotp->l_used-doto;    /* Size of chunk.    */
  1481.         if (chunk > n)
  1482.             chunk = n;
  1483.         if (chunk == 0) {        /* End of line, merge.    */
  1484.             lchange(WFHARD);
  1485.             if (ldelnewline() == FALSE
  1486.             || (kflag!=FALSE && kinsert('\n')==FALSE))
  1487.                 return (FALSE);
  1488.             --n;
  1489.             continue;
  1490.         }
  1491.         lchange(WFEDIT);
  1492.         cp1 = &dotp->l_text[doto];    /* Scrunch text.    */
  1493.         cp2 = cp1 + chunk;
  1494.         if (kflag != FALSE) {        /* Kill?        */
  1495.             while (cp1 != cp2) {
  1496.                 if (kinsert(*cp1) == FALSE)
  1497.                     return (FALSE);
  1498.                 ++cp1;
  1499.             }
  1500.             cp1 = &dotp->l_text[doto];
  1501.         }
  1502.         while (cp2 != &dotp->l_text[dotp->l_used])
  1503.             *cp1++ = *cp2++;
  1504.         dotp->l_used -= chunk;
  1505.         wp = wheadp;            /* Fix windows        */
  1506.         while (wp != NULL) {
  1507.             if (wp->w_dotp==dotp && wp->w_doto>=doto) {
  1508.                 wp->w_doto -= chunk;
  1509.                 if (wp->w_doto < doto)
  1510.                     wp->w_doto = doto;
  1511.             }    
  1512.             if (wp->w_markp==dotp && wp->w_marko>=doto) {
  1513.                 wp->w_marko -= chunk;
  1514.                 if (wp->w_marko < doto)
  1515.                     wp->w_marko = doto;
  1516.             }
  1517.             wp = wp->w_wndp;
  1518.         }
  1519.         n -= chunk;
  1520.     }
  1521.     return (TRUE);
  1522. }
  1523.  
  1524. /*
  1525.  * Delete a newline. Join the current line
  1526.  * with the next line. If the next line is the magic
  1527.  * header line always return TRUE; merging the last line
  1528.  * with the header line can be thought of as always being a
  1529.  * successful operation, even if nothing is done, and this makes
  1530.  * the kill buffer work "right". Easy cases can be done by
  1531.  * shuffling data around. Hard cases require that lines be moved
  1532.  * about in memory. Return FALSE on error and TRUE if all
  1533.  * looks ok. Called by "ldelete" only.
  1534.  */
  1535. ldelnewline()
  1536. {
  1537.     register char    *cp1;
  1538.     register char    *cp2;
  1539.     register LINE    *lp1;
  1540.     register LINE    *lp2;
  1541.     register LINE    *lp3;
  1542.     register WINDOW    *wp;
  1543.  
  1544.     lp1 = curwp->w_dotp;
  1545.     lp2 = lp1->l_fp;
  1546.     if (lp2 == curbp->b_linep) {        /* At the buffer end.    */
  1547.         if (lp1->l_used == 0)        /* Blank line.        */
  1548.             lfree(lp1);
  1549.         return (TRUE);
  1550.     }
  1551.     if (lp2->l_used <= lp1->l_size-lp1->l_used) {
  1552.         cp1 = &lp1->l_text[lp1->l_used];
  1553.         cp2 = &lp2->l_text[0];
  1554.         while (cp2 != &lp2->l_text[lp2->l_used])
  1555.             *cp1++ = *cp2++;
  1556.         wp = wheadp;
  1557.         while (wp != NULL) {
  1558.             if (wp->w_linep == lp2)
  1559.                 wp->w_linep = lp1;
  1560.             if (wp->w_dotp == lp2) {
  1561.                 wp->w_dotp  = lp1;
  1562.                 wp->w_doto += lp1->l_used;
  1563.             }
  1564.             if (wp->w_markp == lp2) {
  1565.                 wp->w_markp  = lp1;
  1566.                 wp->w_marko += lp1->l_used;
  1567.             }
  1568.             wp = wp->w_wndp;
  1569.         }        
  1570.         lp1->l_used += lp2->l_used;
  1571.         lp1->l_fp = lp2->l_fp;
  1572.         lp2->l_fp->l_bp = lp1;
  1573.         free((char *) lp2);
  1574.         return (TRUE);
  1575.     }
  1576.     if ((lp3=lalloc(lp1->l_used+lp2->l_used)) == NULL)
  1577.         return (FALSE);
  1578.     cp1 = &lp1->l_text[0];
  1579.     cp2 = &lp3->l_text[0];
  1580.     while (cp1 != &lp1->l_text[lp1->l_used])
  1581.         *cp2++ = *cp1++;
  1582.     cp1 = &lp2->l_text[0];
  1583.     while (cp1 != &lp2->l_text[lp2->l_used])
  1584.         *cp2++ = *cp1++;
  1585.     lp1->l_bp->l_fp = lp3;
  1586.     lp3->l_fp = lp2->l_fp;
  1587.     lp2->l_fp->l_bp = lp3;
  1588.     lp3->l_bp = lp1->l_bp;
  1589.     wp = wheadp;
  1590.     while (wp != NULL) {
  1591.         if (wp->w_linep==lp1 || wp->w_linep==lp2)
  1592.             wp->w_linep = lp3;
  1593.         if (wp->w_dotp == lp1)
  1594.             wp->w_dotp  = lp3;
  1595.         else if (wp->w_dotp == lp2) {
  1596.             wp->w_dotp  = lp3;
  1597.             wp->w_doto += lp1->l_used;
  1598.         }
  1599.         if (wp->w_markp == lp1)
  1600.             wp->w_markp  = lp3;
  1601.         else if (wp->w_markp == lp2) {
  1602.             wp->w_markp  = lp3;
  1603.             wp->w_marko += lp1->l_used;
  1604.         }
  1605.         wp = wp->w_wndp;
  1606.     }
  1607.     free((char *) lp1);
  1608.     free((char *) lp2);
  1609.     return (TRUE);
  1610. }
  1611.  
  1612. /*
  1613.  * Replace plen characters before dot with argument string.
  1614.  * Control-J characters in st are interpreted as newlines.
  1615.  * There is a casehack disable flag (normally it likes to match
  1616.  * case of replacement to what was there).
  1617.  */
  1618. lreplace(plen, st, f)
  1619. register int    plen;            /* length to remove        */
  1620. char        *st;            /* replacement string        */
  1621. int        f;            /* case hack disable        */
  1622. {
  1623.     register int    rlen;        /* replacement length        */
  1624.     register int    rtype;        /* capitalization         */
  1625.     register int    c;        /* used for random characters    */
  1626.     register int    doto;        /* offset into line        */
  1627.  
  1628.     /*
  1629.      * Find the capitalization of the word that was found.
  1630.      * f says use exact case of replacement string (same thing that
  1631.      * happens with lowercase found), so bypass check.
  1632.      */
  1633.     backchar(TRUE, plen, KRANDOM);
  1634.     rtype = _L;
  1635.     c = lgetc(curwp->w_dotp, curwp->w_doto);
  1636.     if (ISUPPER(c)!=FALSE  &&  f==FALSE) {
  1637.         rtype = _U|_L;
  1638.         if (curwp->w_doto+1 < llength(curwp->w_dotp)) {
  1639.             c = lgetc(curwp->w_dotp, curwp->w_doto+1);
  1640.             if (ISUPPER(c) != FALSE) {
  1641.                 rtype = _U;
  1642.             }
  1643.         }
  1644.     }
  1645.  
  1646.     /*
  1647.      * make the string lengths match (either pad the line
  1648.      * so that it will fit, or scrunch out the excess).
  1649.      * be careful with dot's offset.
  1650.      */
  1651.     rlen = strlen(st);
  1652.     doto = curwp->w_doto;
  1653.     if (plen > rlen)
  1654.         ldelete(plen-rlen, FALSE);
  1655.     else if (plen < rlen) {
  1656.         if (linsert(rlen-plen, ' ') == FALSE)
  1657.             return (FALSE);
  1658.     }
  1659.     curwp->w_doto = doto;
  1660.  
  1661.     /*
  1662.      * do the replacement:  If was capital, then place first 
  1663.      * char as if upper, and subsequent chars as if lower.  
  1664.      * If inserting upper, check replacement for case.
  1665.      */
  1666.     while ((c = *st++&0xff) != '\0') {
  1667.         if ((rtype&_U)!=0  &&  ISLOWER(c)!=0)
  1668.             c = TOUPPER(c);
  1669.         if (rtype == (_U|_L))
  1670.             rtype = _L;
  1671.         if (c == '\n') {
  1672.             if (curwp->w_doto == llength(curwp->w_dotp))
  1673.                 forwchar(FALSE, 1, KRANDOM);
  1674.             else {
  1675.                 ldelete(1, FALSE);
  1676.                 lnewline();
  1677.             }
  1678.         } else if (curwp->w_dotp == curbp->b_linep) {
  1679.             linsert(1, c);
  1680.         } else if (curwp->w_doto == llength(curwp->w_dotp)) {
  1681.             ldelete(1, FALSE);
  1682.             linsert(1, c);
  1683.         } else
  1684.             lputc(curwp->w_dotp, curwp->w_doto++, c);
  1685.     }
  1686.     lchange(WFHARD);
  1687.     return (TRUE);
  1688. }
  1689.  
  1690. /*
  1691.  * Delete all of the text
  1692.  * saved in the kill buffer. Called by commands
  1693.  * when a new kill context is being created. The kill
  1694.  * buffer array is released, just in case the buffer has
  1695.  * grown to immense size. No errors.
  1696.  */
  1697. kdelete()
  1698. {
  1699.     if (kbufp != NULL) {
  1700.         free((char *) kbufp);
  1701.         kbufp = NULL;
  1702.         kused = 0;
  1703.         ksize = 0;
  1704.     }
  1705. }
  1706.  
  1707. /*
  1708.  * Insert a character to the kill buffer,
  1709.  * enlarging the buffer if there isn't any room. Always
  1710.  * grow the buffer in chunks, on the assumption that if you
  1711.  * put something in the kill buffer you are going to put
  1712.  * more stuff there too later. Return TRUE if all is
  1713.  * well, and FALSE on errors. Print a message on
  1714.  * errors.
  1715.  */
  1716. kinsert(c)
  1717. {
  1718.     register char    *nbufp;
  1719.     register int    i;
  1720.  
  1721.     if (kused == ksize) {
  1722.         if ((nbufp=malloc(ksize+KBLOCK)) == NULL) {
  1723.             eprintf("Too many kills");
  1724.             return (FALSE);
  1725.         }
  1726.         for (i=0; i<ksize; ++i)
  1727.             nbufp[i] = kbufp[i];
  1728.         if (kbufp != NULL)
  1729.             free((char *) kbufp);
  1730.         kbufp  = nbufp;
  1731.         ksize += KBLOCK;
  1732.     }
  1733.     kbufp[kused++] = c;
  1734.     return (TRUE);
  1735. }
  1736.  
  1737. /*
  1738.  * This function gets characters from
  1739.  * the kill buffer. If the character index "n" is
  1740.  * off the end, it returns "-1". This lets the caller
  1741.  * just scan along until it gets a "-1" back.
  1742.  */
  1743. kremove(n)
  1744. {
  1745.     if (n >= kused)
  1746.         return (-1);
  1747.     return (kbufp[n] & 0xFF);
  1748. }
  1749. SHAR_EOF
  1750. if test 14554 -ne "`wc -c < 'line.c'`"
  1751. then
  1752.     echo shar: error transmitting "'line.c'" '(should have been 14554 characters)'
  1753. fi
  1754. fi
  1755. echo shar: extracting "'main.c'" '(6208 characters)'
  1756. if test -f 'main.c'
  1757. then
  1758.     echo shar: will not over-write existing file "'main.c'"
  1759. else
  1760. cat << \SHAR_EOF > 'main.c'
  1761. /*
  1762.  * Name:    MicroEMACS
  1763.  *        Mainline, macro commands.
  1764.  * Version:    29
  1765.  * Last edit:    05-Feb-86
  1766.  * By:        rex::conroy
  1767.  *        decvax!decwrl!dec-rhea!dec-rex!conroy
  1768.  */
  1769. #include    "def.h"
  1770.  
  1771. int    thisflag;            /* Flags, this command        */
  1772. int    lastflag;            /* Flags, last command        */
  1773. int    curgoal;            /* Goal column            */
  1774. BUFFER    *curbp;                /* Current buffer        */
  1775. WINDOW    *curwp;                /* Current window        */
  1776. BUFFER    *bheadp;            /* BUFFER listhead        */
  1777. WINDOW    *wheadp;            /* WINDOW listhead        */
  1778. BUFFER    *blistp;            /* Buffer list BUFFER        */
  1779. short    kbdm[NKBDM] = (KCTLX|')');    /* Macro            */
  1780. short    *kbdmip;            /* Input  for above        */
  1781. short    *kbdmop;            /* Output for above        */
  1782. char    pat[NPAT];            /* Pattern            */
  1783. SYMBOL    *symbol[NSHASH];        /* Symbol table listhead.    */
  1784. SYMBOL    *binding[NKEYS];        /* Key bindings.        */
  1785.  
  1786. main(argc, argv)
  1787. char    *argv[];
  1788. {
  1789.     register int    c;
  1790.     register int    f;
  1791.     register int    n;
  1792.     register int    mflag;
  1793.     char        bname[NBUFN];
  1794.  
  1795.     strcpy(bname, "main");            /* Get buffer name.    */
  1796.     if (argc > 1)
  1797.         makename(bname, argv[1]);
  1798.     vtinit();                /* Virtual terminal.    */
  1799.     edinit(bname);                /* Buffers, windows.    */
  1800.     keymapinit();                /* Symbols, bindings.    */
  1801.     if (argc > 1) {
  1802.         update();
  1803.         readin(argv[1]);
  1804.     }
  1805.     lastflag = 0;                /* Fake last flags.    */
  1806. loop:
  1807.     update();                /* Fix up the screen.    */
  1808.     c = getkey();
  1809.     if (epresf != FALSE) {
  1810.         eerase();
  1811.         update();
  1812.     }
  1813.     f = FALSE;
  1814.     n = 1;
  1815.     if (c == (KCTRL|'U')) {            /* ^U, start argument.    */
  1816.         f = TRUE;
  1817.         n = 4;
  1818.         while ((c=getkey()) == (KCTRL|'U'))
  1819.             n *= 4;
  1820.         if ((c>='0' && c<='9') || c=='-') {
  1821.             if (c == '-') {
  1822.                 n = 0;
  1823.                 mflag = TRUE;
  1824.             } else {
  1825.                 n = c - '0';
  1826.                 mflag = FALSE;
  1827.             }
  1828.             while ((c=getkey())>='0' && c<='9')
  1829.                 n = 10*n + c - '0';
  1830.             if (mflag != FALSE)
  1831.                 n = -n;
  1832.         }
  1833.     }
  1834.     if (kbdmip != NULL) {            /* Save macro strokes.    */
  1835.         if (c!=(KCTLX|')') && kbdmip>&kbdm[NKBDM-6]) {
  1836.             ctrlg(FALSE, 0, KRANDOM);
  1837.             goto loop;
  1838.         }
  1839.         if (f != FALSE) {
  1840.             *kbdmip++ = (KCTRL|'U');
  1841.             *kbdmip++ = n;
  1842.         }
  1843.         *kbdmip++ = c;
  1844.     }
  1845.     execute(c, f, n);            /* Do it.        */
  1846.     goto loop;
  1847. }
  1848.  
  1849. /*
  1850.  * Command execution. Look up the binding in the the
  1851.  * binding array, and do what it says. Return a very bad status
  1852.  * if there is no binding, or if the symbol has a type that
  1853.  * is not usable (there is no way to get this into a symbol table
  1854.  * entry now). Also fiddle with the flags.
  1855.  */
  1856. execute(c, f, n)
  1857. {
  1858.     register SYMBOL    *sp;
  1859.     register int    status;
  1860.  
  1861.     if ((sp=binding[c]) != NULL) {
  1862.         thisflag = 0;
  1863.         status = (*sp->s_funcp)(f, n, c);
  1864.         lastflag = thisflag;
  1865.         return (status);
  1866.     }
  1867.     lastflag = 0;
  1868.     return (ABORT);
  1869. }
  1870.  
  1871. /*
  1872.  * Initialize all of the buffers
  1873.  * and windows. The buffer name is passed down as
  1874.  * an argument, because the main routine may have been
  1875.  * told to read in a file by default, and we want the
  1876.  * buffer name to be right.
  1877.  */
  1878. edinit(bname)
  1879. char    bname[];
  1880. {
  1881.     register BUFFER    *bp;
  1882.     register WINDOW    *wp;
  1883.  
  1884.     bp = bfind(bname, TRUE);        /* Text buffer.        */
  1885.     blistp = bcreate("");            /* Special list buffer.    */
  1886.     wp = (WINDOW *) malloc(sizeof(WINDOW));    /* Initial window.    */
  1887.     if (bp==NULL || wp==NULL || blistp==NULL)
  1888.         abort();
  1889.     curbp  = bp;                /* Current ones.    */
  1890.     wheadp = wp;
  1891.     curwp  = wp;
  1892.     wp->w_wndp  = NULL;            /* Initialize window.    */
  1893.     wp->w_bufp  = bp;
  1894.     bp->b_nwnd  = 1;            /* Displayed.        */
  1895.     wp->w_linep = bp->b_linep;
  1896.     wp->w_dotp  = bp->b_linep;
  1897.     wp->w_doto  = 0;
  1898.     wp->w_markp = NULL;
  1899.     wp->w_marko = 0;
  1900.     wp->w_toprow = 0;
  1901.     wp->w_ntrows = nrow-2;            /* 2 = mode, echo.    */
  1902.     wp->w_force = 0;
  1903.     wp->w_flag  = WFMODE|WFHARD;        /* Full.        */
  1904. }
  1905.     
  1906. /*
  1907.  * Fancy quit command, as implemented
  1908.  * by Jeff. If the current buffer has changed
  1909.  * do a write current buffer. Otherwise run a command
  1910.  * interpreter in a subjob. Two of these will get you
  1911.  * out. Bound to "C-Z".
  1912.  */
  1913. jeffexit(f, n, k)
  1914. {
  1915.     if ((curbp->b_flag&BFCHG) != 0)        /* Changed.        */
  1916.         return (filesave(f, n, KRANDOM));
  1917.     return (spawncli(f, n, KRANDOM));    /* Suspend.        */
  1918. }
  1919.  
  1920. /*
  1921.  * Quit command. If an argument, always
  1922.  * quit. Otherwise confirm if a buffer has been
  1923.  * changed and not written out. Normally bound
  1924.  * to "C-X C-C".
  1925.  */
  1926. quit(f, n, k)
  1927. {
  1928.     register int    s;
  1929.  
  1930.     if (f != FALSE                /* Argument forces it.    */
  1931.     || anycb() == FALSE            /* All buffers clean.    */
  1932.     || (s=eyesno("Quit")) == TRUE) {    /* User says it's OK.    */
  1933.         vttidy();
  1934.         exit(GOOD);
  1935.     }
  1936.     return (s);
  1937. }
  1938.  
  1939. /*
  1940.  * Begin a keyboard macro.
  1941.  * Error if not at the top level
  1942.  * in keyboard processing. Set up
  1943.  * variables and return.
  1944.  */
  1945. ctlxlp(f, n, k)
  1946. {
  1947.     if (kbdmip!=NULL || kbdmop!=NULL) {
  1948.         eprintf("Not now");
  1949.         return (FALSE);
  1950.     }
  1951.     eprintf("[Start macro]");
  1952.     kbdmip = &kbdm[0];
  1953.     return (TRUE);
  1954. }
  1955.  
  1956. /*
  1957.  * End keyboard macro. Check for
  1958.  * the same limit conditions as the
  1959.  * above routine. Set up the variables
  1960.  * and return to the caller.
  1961.  */
  1962. ctlxrp(f, n, k)
  1963. {
  1964.     if (kbdmip == NULL) {
  1965.         eprintf("Not now");
  1966.         return (FALSE);
  1967.     }
  1968.     eprintf("[End macro]");
  1969.     kbdmip = NULL;
  1970.     return (TRUE);
  1971. }
  1972.  
  1973. /*
  1974.  * Execute a macro.
  1975.  * The command argument is the
  1976.  * number of times to loop. Quit as
  1977.  * soon as a command gets an error.
  1978.  * Return TRUE if all ok, else
  1979.  * FALSE.
  1980.  */
  1981. ctlxe(f, n, k)
  1982. {
  1983.     register int    c;
  1984.     register int    af;
  1985.     register int    an;
  1986.     register int    s;
  1987.  
  1988.     if (kbdmip!=NULL || kbdmop!=NULL) {
  1989.         eprintf("Not now");
  1990.         return (FALSE);
  1991.     }
  1992.     if (n <= 0) 
  1993.         return (TRUE);
  1994.     do {
  1995.         kbdmop = &kbdm[0];
  1996.         do {
  1997.             af = FALSE;
  1998.             an = 1;
  1999.             if ((c = *kbdmop++) == (KCTRL|'U')) {
  2000.                 af = TRUE;
  2001.                 an = *kbdmop++;
  2002.                 c  = *kbdmop++;
  2003.             }
  2004.             s = TRUE;
  2005.         } while (c!=(KCTLX|')') && (s=execute(c, af, an))==TRUE);
  2006.         kbdmop = NULL;
  2007.     } while (s==TRUE && --n);
  2008.     return (s);
  2009. }
  2010.  
  2011. /*
  2012.  * Abort.
  2013.  * Beep the beeper.
  2014.  * Kill off any keyboard macro,
  2015.  * etc., that is in progress.
  2016.  * Sometimes called as a routine,
  2017.  * to do general aborting of
  2018.  * stuff.
  2019.  */
  2020. ctrlg(f, n, k)
  2021. {
  2022.     ttbeep();
  2023.     if (kbdmip != NULL) {
  2024.         kbdm[0] = (KCTLX|')');
  2025.         kbdmip  = NULL;
  2026.     }
  2027.     return (ABORT);
  2028. }
  2029.  
  2030. /*
  2031.  * Display the version. All this does
  2032.  * is copy the text in the external "version" array into
  2033.  * the message system, and call the message reading code.
  2034.  * Don't call display if there is an argument.
  2035.  */
  2036. showversion(f, n, k)
  2037. {
  2038.     register char    **cpp;
  2039.     register char    *cp;
  2040.  
  2041.     cpp = &version[0];
  2042.     while ((cp = *cpp++) != NULL) {
  2043.         if (writemsg(cp) == FALSE)
  2044.             return (FALSE);
  2045.     }
  2046.     if (f != FALSE)                /* No display if arg.    */
  2047.         return (TRUE);
  2048.     return (readmsg());
  2049. }
  2050. SHAR_EOF
  2051. if test 6208 -ne "`wc -c < 'main.c'`"
  2052. then
  2053.     echo shar: error transmitting "'main.c'" '(should have been 6208 characters)'
  2054. fi
  2055. fi
  2056. exit 0
  2057. #    End of shell archive
  2058.